# 面向对象: 封装, 继承, 多态
# 封装: 将数据和方法封装在类中, 通过类的接口访问
# 封装: 指的是隐藏对象中一些不希望外部访问的属性和方法

class Person:
    name = "Leslie"
    __age = 29  # 私有属性: 只能在类的内部访问, 无法通过对象访问
    def intro(self):
        print(f"{Person.name}的年龄是{self.__age}岁")
        return self.__age

# 隐藏属性: 只允许在类的内部使用,无法通过对象访问 __attr__
p1 = Person()
print(p1.name)  # Leslie
# print(p1.age) # AttributeError: 'Person' object has no attribute 'age'

# 访问隐藏属性 - 1: 可以通过别名: _ClassName__attribute
# print(Person._Person__age)  # 29
# p1._Person__age = 30  # 修改隐藏属性
# print(p1._Person__age)  # 30

# 访问隐藏属性 - 2: 可以通过类的方法访问
age = p1.intro()
print(age)

# xxx 普通属性/方法，如果是在类中定义的，则类可以在任意地方使用
# __xx 双下滑线属性/方法，表示隐藏属性/方法，只能在类的内部访问, 不会被继承. 魔术方法,
# _xx 单下划线属性/方法，表私有属性/方法， 如果定义在类中，外部可以使用，但可以被继承，但是无法从from导出，一般是为了避免和python内置方法冲突


class Man:
    name = "Leslie"
    __age = 18 # 隐藏属性
    _sex = "male" # 单下划线属性
    def __play(self):
        print("play")
    def drink(self):
        print("drink")
        Man.__play(self) # 在类的内部访问 不推荐的方式
        self.__play() # 推荐的方式, 使用对象 可以在类的内部访问隐藏方法

m1 = Man()
# print(m1.sex) # AttributeError: 'Man' object has no attribute 'sex'
print(m1._sex) # male
print(Man._Man__age)  # 18
m1.drink()
# m1.__play() # AttributeError: 'Man' object has no attribute 'play'


class Girl:
    def _buy(self):
        print("buy")

g1 = Girl()
g1._buy()


# 私有属性和方法的作用:  防止外部直接访问和修改, 保持数据的完整性
# 私有属性和方法, 使用单下划线定义
# 私有属性和方法, 使用 对象._attrName 访问 和 对象.funName() 访问

# 隐藏属性和方法的作用:
# 访问隐藏属性 -  可以通过别名: _ClassName__attribute
# print(Person._Person__age)  # 29
# p1._Person__age = 30  # 修改隐藏属性
# print(p1._Person__age)  # 30